package com.net.xpay.admin.secutiry;


import com.google.common.base.Strings;
import com.net.common.util.ServletUtil;
import com.net.common.util.StreamUtil;
import com.net.xpay.common.domain.admin.rbac.AdminUser;
import com.net.xpay.common.domain.admin.rbac.Permission;
import com.net.xpay.common.manager.admin.rbac.AdminUserManager;
import com.net.xpay.common.service.admin.rbac.PermissionService;
import com.net.xpay.core.constant.AdminWebConstant;
import com.net.xpay.core.constant.PoseidonErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.List;


/**
 * on 01/02/2018.
 */
@Slf4j
@Component
public class AccessDecisionManagerImpl implements AccessDecisionManager {
    @Autowired
    private SecurityHelper securityHelper;

    @Autowired
    private AdminUserManager adminUserManager;

    @Autowired
    private PermissionService permissionService;

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        HttpServletRequest request = ((FilterInvocation) object).getRequest();
        HttpServletResponse response = ((FilterInvocation) object).getResponse();
        String path = ServletUtil.PATH_SEP + ServletUtil.getTopmostPath(request);
        String url = request.getRequestURI();
        if (Strings.isNullOrEmpty(path)) {
            throw new WebInsufficientAuthException(PoseidonErrorCode.REQUEST_URL_ILLEGAL, "请求链接错误,path为空");
        }
        if (AdminWebConstant.COMMON.equalsIgnoreCase(path)) {
            return;
        }
        if ("/admin/partner-user-filings/register".equalsIgnoreCase(url)) {
            return;
        }

        if (request.getRequestedSessionId() != null
                && !request.isRequestedSessionIdValid()) {
            securityHelper.removeInvalidSessionCookie(request, response);
            throw new WebInsufficientAuthException(PoseidonErrorCode.NEED_LOGIN, "请先登录");
        }

        if (authentication instanceof AnonymousAuthenticationToken) {
            securityHelper.removeInvalidSessionCookie(request, response);
            throw new WebInsufficientAuthException(PoseidonErrorCode.NEED_LOGIN, "请先登录");
        }

        Long adminUserId = (Long) authentication.getPrincipal();
        if (adminUserId == null) {
            securityHelper.removeInvalidSessionCookie(request, response);
            throw new WebInsufficientAuthException(PoseidonErrorCode.NEED_LOGIN, "请先登录");
        }

        //重新查一下
        AdminUser adminUser = adminUserManager.getById(adminUserId);

        if (adminUser == null) {
            securityHelper.removeInvalidSessionCookie(request, response);
            throw new WebInsufficientAuthException(PoseidonErrorCode.NEED_LOGIN, "请先登录");
        }

        if (!adminUser.getEnabled()) {
            throw new WebInsufficientAuthException(PoseidonErrorCode.PARAMETER_ILLEGAL, "当前账号不存在");
        }

        List<Permission> permissions = permissionService.findByAdminUserId(adminUser.getId());
        adminUser.setPermissions(permissions);
        boolean isSuperAdmin = false;
        for (Permission permission : permissions) {
            if ("ADMIN".equals(permission.getName())) {
                isSuperAdmin = true;
                break;
            }
        }
        adminUser.setSuperAdmin(isSuperAdmin);

        //for CurrentOperatorArgumentResolver
        request.setAttribute(AdminWebConstant.REQUEST_USER_ATTR, adminUser);

        //用户权限刷新，不然一直用的session里缓存的

        Collection<GrantedAuthority> authorities = StreamUtil.map(permissions, permission -> new SimpleGrantedAuthority(permission.getName()));
        authentication = new UsernamePasswordAuthenticationToken(adminUser.getId(), null, authorities);
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }


    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}
